#ifndef __M_FMT_H__
#define __M_FMT_H__//日志输出

#include "util.hpp"
#include "message.hpp"
#include "level.hpp"
#include <memory>
#include <vector>
#include <tuple>
//这段代码的主要作用是对代码进行格式化，其中，上半部分是进行格式项，下半部分是进行格式化
//格式项：在格式化字符串中用于指定输出数据格式和位置的占位符或说明符。
//格式化：将原始数据按照指定的格式项转换为字符串的过程。
namespace bitlog{
    class FormatItem{//格式项
        public:
        using ptr = std::shared_ptr<FormatItem>;//定义了一个类型别名ptr，它是FormatItem的std::shared_ptr智能指针类型
        virtual ~FormatItem() {}//声明并定义了一个虚析构函数，确保派生类对象能够正确通过基类指针被销毁
        virtual void format(std::ostream &os, const LogMsg &msg) = 0;
        //声明了一个纯虚函数format，要求派生类必须实现这个函数，用于格式化日志消息到输出流
    };
    class MsgFormatItem : public FormatItem{//消息格式项
        public:
        MsgFormatItem(const std::string &str = ""){}//构造函数，默认参数为空字符串，用于创建MsgFormatItem对象
        virtual void format(std::ostream &os, const LogMsg &msg) {//虚函数，定义了一个格式化日志消息的方法
            os << msg._payload;//将日志消息的有效负载（payload）输出到给定的输出流中
            //有效负载（Payload）是指在网络通信或数据包中携带的实际数据部分
        }
    };
    class LevelFormatItem : public FormatItem{//级别格式项
        public:
        LevelFormatItem(const std::string &str = ""){}
        virtual void format(std::ostream &os, const LogMsg &msg) {
            os << LogLevel::toString(msg._level);//将日志级别转换为字符串并输出
        }
    };
    class NameFormatItem : public FormatItem{//名称格式项
        public:
        NameFormatItem(const std::string &str = ""){}
        virtual void format(std::ostream &os, const LogMsg &msg) {
            os << msg._name;//msg对象的_name成员变量的值输出到os流中
        }
    };
    class ThreadFormatItem : public FormatItem{//线程格式项
        public:
        ThreadFormatItem(const std::string &str = ""){}
        virtual void format(std::ostream &os, const LogMsg &msg) {
            os << msg._tid;//msg对象的_tid成员变量的值输出到输出流os中
        }
    };
    class TimeFormatItem : public FormatItem{//时间格式项
        private:
        std::string _format;//存储某种格式化的文本
    public:
        TimeFormatItem(const std::string &format = "%H:%M:%S"):_format(format){//自动使用 "%H:%M:%S" 作为默认值
            if (format.empty()) _format = "%H:%M:%S";
        }
        virtual void format(std::ostream &os, const LogMsg &msg) {
            time_t t = msg._ctime;
            struct tm lt;
            localtime_r(&t, &lt);
            char tmp[128];
            strftime(tmp, 127, _format.c_str(), &lt);
            os << tmp;
        }

    };
    class CFileFormatItem : public FormatItem {//文件格式项
        public:
        public:
        CFileFormatItem(const std::string &str = ""){}
        virtual void format(std::ostream &os, const LogMsg &msg) {
            os << msg._file;//这行代码将 msg 对象的 _file 成员变量的值输出到输出流 os 中
        }
    };
    class CLineFormatItem : public FormatItem{
        public:
        CLineFormatItem(const std::string &str = ""){}
        virtual void format(std::ostream &os, const LogMsg &msg) {
            os << msg._line;//这行代码将 msg 对象的 _line 成员变量的值输出到输出流 os 中
        }
    };
    class TabFormatItem : public FormatItem{
        public:
        TabFormatItem(const std::string &str = ""){}
        virtual void format(std::ostream &os, const LogMsg &msg) {
            os << "\t";//这行代码向输出流 os 中插入一个制表符（Tab）
        }
    };
    class NLineFormatItem : public FormatItem{
        public:
        NLineFormatItem(const std::string &str = ""){}
        virtual void format(std::ostream &os, const LogMsg &msg) {
            os << "\n";//这行代码向输出流 os 中插入一个换行符，使后续的输出内容出现在新的一行上
        }
    };
    class OtherFormatItem : public FormatItem{//其他格式项
        private:
        std::string _str;
        public:
        OtherFormatItem(const std::string &str = ""):_str(str){}
        virtual void format(std::ostream &os, const LogMsg &msg) {
            os << _str;//这行代码将字符串变量 _str 的内容输出到输出流 os 中
        }

    };
    class Formatter {//格式化
    public:
        using ptr = std::shared_ptr<Formatter>;
        /*
            %d 日期
            %T 缩进
            %t 线程id
            %p 日志级别
            %c 日志器名称
            %f 文件名
            %l 行号
            %m 日志消息
            %n 换行
        */
        //时间{年-月-日 时:分:秒}缩进 线程ID 缩进 [日志级别] 缩进 [日志名称] 缩进 文件名:行号 缩进 消息换行
        //告诉Formatter如何整理和展示日志消息
        Formatter(const std::string &pattern = "[%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n"):// Formatter的构造函数
            _pattern(pattern){
            assert(parsePattern());//用于检查 parsePattern() 函数的返回值是否为真
        }
        const std::string pattern() { return _pattern; }
        // 将LogMsg格式化为字符串
        //专门负责整理某一类信息的助手
        std::string format(const LogMsg &msg) {
            std::stringstream ss;
            for (auto &it : _items) {
                it->format(ss, msg);// 遍历_items，格式化并写入ss
            }
            return ss.str();
        }
        // 将LogMsg格式化并输出到ostream
        //把日志消息的不同部分整理成格式字符串中指定的样子
        std::ostream& format(std::ostream &os, const LogMsg &msg) {
            for (auto &it : _items) {
                it->format(os, msg);// 遍历_items，格式化并输出到os 
            }
            return os;
        }
        // 根据格式控制符和子格式创建FormatItem对象
        //Formatter会把整理好的日志消息输出到一个指定的地方
        FormatItem::ptr createItem(const std::string &fc, const std::string &subfmt) {
            if (fc == "m") return FormatItem::ptr(new MsgFormatItem(subfmt));// 创建消息格式项
            if (fc == "p") return FormatItem::ptr(new LevelFormatItem(subfmt));// 创建级别格式项
            if (fc == "c") return FormatItem::ptr(new NameFormatItem(subfmt));//其余类似
            if (fc == "t") return FormatItem::ptr(new ThreadFormatItem(subfmt));
            if (fc == "n") return FormatItem::ptr(new NLineFormatItem(subfmt));
            if (fc == "d") return FormatItem::ptr(new TimeFormatItem(subfmt));
            if (fc == "f") return FormatItem::ptr(new CFileFormatItem(subfmt));
            if (fc == "l") return FormatItem::ptr(new CLineFormatItem(subfmt));
            if (fc == "T") return FormatItem::ptr(new TabFormatItem(subfmt));// 创建制表符格式项
            return FormatItem::ptr();
        }
        //pattern解析 
        bool parsePattern() {//解析模式
            //std::string _pattern = "sg{}fsg%d{%H:%M:%S}%Tsdf%t%T[%p]%T[%c]%T%f:%l%T%m%n  ";
            //std::cout << _pattern << std::endl;
            //每个要素分为三部分：
            //  格式化字符  : %d  %T  %p...
            //  对应的输出子格式 ： {%H:%M:%S}
            //  对应数据的类型 ： 0-表示原始字符串，也就是非格式化字符，1-表示格式化数据类型
            //  默认格式 "%d{%H:%M:%S}%T%t%T[%p]%T[%c]%T%f:%l%T%m%n"
            std::vector<std::tuple<std::string, std::string, int>> //arry;定义一个存储元组的向量，用于存放解析结果（格式化键、格式化值、是否有子格式）  
            std::string format_key;//存放%后的格式化字符
            std::string format_val;//存放格式化字符后边 {} 中的子格式字符串
            std::string string_row;//存放原始的非格式化字符
            bool sub_format_error = false;// 标记子格式解析过程中是否出错  
            int pos = 0;
            while (pos < _pattern.size()) {// 遍历模式字符串  
            // 如果当前字符不是%，则将其添加到原始字符串中，并移动索引 
                if (_pattern[pos] != '%') {
                    string_row.append(1, _pattern[pos++]);
                    continue;
                }
                // 如果连续遇到两个%%，则将其视为一个%字符添加到原始字符串中，并移动索引两位  
                if (pos+1 < _pattern.size() && _pattern[pos+1] == '%') {
                    string_row.append(1, '%');
                    pos += 2;
                    continue;
                }
                // 如果原始字符串非空，则将其作为一个非格式化字符串元组添加到arry中，并清空原始字符串 
                if (string_row.empty() == false) {
                    arry.push_back(std::make_tuple(string_row, "", 0));
                    string_row.clear();
                }
                //当前位置是%字符位置
                pos += 1;//pos指向格式化字符位置
                // 如果当前字符是字母，则将其作为格式化键保存
                if (pos < _pattern.size() && isalpha(_pattern[pos])) {
                    format_key = _pattern[pos];//保存格式化字符
                }else {
                    std::cout << &_pattern[pos-1] << "位置附近格式错误！\n";
                    return false;
                }
                // 如果存在子格式（即{}内的内容），则进入子格式解析
                pos += 1;//pos指向格式化字符的下一个位置，判断是否包含有子格式 %d{%Y-%m-%d}
                if (pos < _pattern.size() && _pattern[pos] == '{') {
                    sub_format_error = true;
                    pos += 1;//pos指向花括号下一个字符处
                    // 解析子格式内容，直到遇到}字符
                    while(pos < _pattern.size()) {
                        if (_pattern[pos] == '}') {
                            sub_format_error = false;
                            pos += 1;//让pos指向}的下一个字符处
                            break;
                        }
                        format_val.append(1, _pattern[pos++]);
                    }
                }
                // 将解析得到的格式化键和子格式（或空字符串）作为一个元组添加到arry中
                arry.push_back(std::make_tuple(format_key, format_val, 1));
                format_key.clear();// 清空格式化键和子格式字符串，为下一次解析做准备  
                format_val.clear();
            }
            // 如果在遍历结束后发现子格式错误，则报错并返回false
            if (sub_format_error) {
                std::cout << "{}对应出错\n";
                return false;
            }
            if (string_row.empty() == false) arry.push_back(std::make_tuple(string_row, "", 0));
            if (format_key.empty() == false) arry.push_back(std::make_tuple(format_key, format_val, 1));
            // 遍历arry中的元组，根据是否包含子格式创建相应的FormatItem对象，并将其添加到_items容器中  
            for (auto &it : arry) {
                if (std::get<2>(it) == 0) {
                    FormatItem::ptr fi(new OtherFormatItem(std::get<0>(it)));
                    _items.push_back(fi);
                }else {
                    FormatItem::ptr fi = createItem(std::get<0>(it), std::get<1>(it));
                    if (fi.get() == nullptr) {
                        std::cout << "没有对应的格式化字符: %" <<  std::get<0>(it) << std::endl;
                        return false;
                    }
                    _items.push_back(fi);
                }
            }
            return true;
        }
    private:
        std::string _pattern;
        std::vector<FormatItem::ptr> _items;
    };
}
//代码的上半部分
//这些类都是日志格式化项，用于将日志消息的不同部分（如消息内容、级别、名称、线程、时间、文件、行号等）按照特定格式输出到输出流中
//这些代码定义了一个Formatter类，用于根据指定的格式模式（pattern）将日志消息（LogMsg）格式化为字符串或输出到输出流（std::ostream）
//FormatItem是一个基类，具体的格式化项（如时间、线程ID等）由FormatItem的派生类实现
//它解析格式模式，创建相应的格式化项（FormatItem），然后遍历这些格式化项来格式化日志消息的不同部分
//